home *** CD-ROM | disk | FTP | other *** search
/ Mac Format 1995 June / MacFormat 25.iso / Shareware City / Developers / OutOfPhase1.1 Source / OutOfPhase Folder / PlayAIFFFile.c < prev    next >
Text File  |  1995-01-04  |  28KB  |  789 lines

  1. /* PlayAIFFFile.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "PlayAIFFFile.h"
  31. #include "BufferedFileInput.h"
  32. #include "Files.h"
  33. #include "Alert.h"
  34. #include "SampleConsts.h"
  35. #include "SoundOutput.h"
  36. #include "DataMunging.h"
  37. #include "EventLoop.h"
  38. #include "Memory.h"
  39. #include "SynthProgressWindow.h"
  40.  
  41.  
  42. #define FRAMESPERBUFFER (8192L)
  43. #define NUMBEROFBUFFERS (16)
  44. #define INITIALNUMBUFFERS (3)
  45.  
  46.  
  47. /* AIFF/AIFF-C File Format: */
  48. /*     "FORM" */
  49. /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  50. /*     4-byte type */
  51. /*        "AIFF" = AIFF format file */
  52. /*        "AIFC" = AIFF-C format file */
  53. /* in any order, these chunks can occur: */
  54. /*   Version Chunk (this only occurs in AIFF-C files) */
  55. /*     "FVER" */
  56. /*     4-byte big endian length, which should always be the value 4 (four) */
  57. /*     4-byte date code.  this is probably 0xA2805140 (stored big endian), but it */
  58. /*          probably doesn't matter. */
  59. /*   Common Chunk for AIFF files */
  60. /*     "COMM" */
  61. /*     4-byte big endian length. */
  62. /*        always 18 for AIFF files */
  63. /*     2-byte big endian number of channels */
  64. /*     4-byte big endian number of sample frames */
  65. /*     2-byte big endian number of bits per sample */
  66. /*        a value in the domain 1..32 */
  67. /*     10-byte extended precision number of frames per second */
  68. /*   Common Chunk for AIFF-C files */
  69. /*     "COMM" */
  70. /*     4-byte big endian length. */
  71. /*        22 + compression method string length for AIFF-C files */
  72. /*     2-byte big endian number of channels */
  73. /*     4-byte big endian number of sample frames */
  74. /*     2-byte big endian number of bits per sample */
  75. /*        a value in the domain 1..32 */
  76. /*     10-byte extended precision number of frames per second */
  77. /*     4-byte character code ID for the compression method */
  78. /*        "NONE" means there is no compression method used */
  79. /*     some characters in a string identifying the compression method */
  80. /*        this must be padded to an even number of bytes, but the pad is */
  81. /*        NOT included in the length descriptor for the chunk. */
  82. /*        for uncompressed data, the string should be */
  83. /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  84. /*        the total chunk length is thus 38 bytes. */
  85. /*   Sound Data Chunk */
  86. /*     "SSND" */
  87. /*     4-byte big endian number of bytes in sample data array */
  88. /*     4-byte big endian offset to the first byte of sample data in the array */
  89. /*     4-byte big endian number of bytes to which the sound data is aligned. */
  90. /*     any length vector of raw sound data. */
  91. /*        this must be padded to an even number of bytes, but the pad is */
  92. /*        NOT included in the length descriptor for the chunk. */
  93. /*        Samples are stored in an integral number of bytes, the smallest that */
  94. /*        is required for the specified number of bits.  If this is not an even */
  95. /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  96. /*        Multichannel sound is interleaved with the left channel first. */
  97. static void                        PlayTheFile(BufferedInputRec* File, SynthWinRec* Window)
  98.     {
  99.         char                                CharBuff[4];
  100.         MyBoolean                        IsAnAIFFCFile;
  101.         long                                FormChunkLength;
  102.         long                                NumBits;
  103.         MyBoolean                        NumBitsIsValid = False;
  104.         NumChannelsType            NumChannels;
  105.         MyBoolean                        NumChannelsIsValid = False;
  106.         long                                SamplingRate;
  107.         MyBoolean                        SamplingRateIsValid = False;
  108.         unsigned long                NumSampleFrames;
  109.         MyBoolean                        NumSampleFramesIsValid = False;
  110.         MyBoolean                        DiskErrorOccurred;
  111.  
  112.         /*     "FORM" */
  113.         if (!ReadBufferedInput(File,4,CharBuff))
  114.             {
  115.              DiskErrorPoint1:
  116.                 AlertHalt("Unable to read data from the file.",NIL);
  117.              ExitTheProcedureErrorPoint:
  118.                 return;
  119.             }
  120.         if (!MemEqu(CharBuff,"FORM",4))
  121.             {
  122.              BadFilePoint1:
  123.                 AlertHalt("The file is not an AIFF or AIFF-C file.",NIL);
  124.                 goto ExitTheProcedureErrorPoint;
  125.             }
  126.  
  127.         /*     4-byte big endian form chunk length descriptor (minus 8 for "FORM" & this) */
  128.         if (!ReadBufferedUnsignedLongBigEndian(File,(unsigned long*)&FormChunkLength))
  129.             {
  130.                 goto DiskErrorPoint1;
  131.             }
  132.  
  133.         /*     4-byte type */
  134.         /*        "AIFF" = AIFF format file */
  135.         /*        "AIFC" = AIFF-C format file */
  136.         if (!ReadBufferedInput(File,4,CharBuff))
  137.             {
  138.                 goto DiskErrorPoint1;
  139.             }
  140.         if (MemEqu(CharBuff,"AIFF",4))
  141.             {
  142.                 IsAnAIFFCFile = False;
  143.             }
  144.         else if (MemEqu(CharBuff,"AIFC",4))
  145.             {
  146.                 IsAnAIFFCFile = True;
  147.             }
  148.         else
  149.             {
  150.              UnknownAIFFFilePoint:
  151.                 AlertHalt("The file is not a variant of AIFF or AIFF-C file that I can deal with.",NIL);
  152.                 goto ExitTheProcedureErrorPoint;
  153.             }
  154.         FormChunkLength -= 4;
  155.  
  156.         /* now, read in chunks until we die */
  157.         DiskErrorOccurred = False;
  158.         while (!DiskErrorOccurred && (FormChunkLength > 0))
  159.             {
  160.                 long                            LocalChunkLength;
  161.  
  162.                 /* get the chunk type */
  163.                 if (!ReadBufferedInput(File,4,CharBuff))
  164.                     {
  165.                         goto DiskErrorPoint1;
  166.                     }
  167.                 /* get the chunk length */
  168.                 if (!ReadBufferedUnsignedLongBigEndian(File,(unsigned long*)&LocalChunkLength))
  169.                     {
  170.                         goto DiskErrorPoint1;
  171.                     }
  172.                 FormChunkLength -= 8;
  173.                 /* adjust for even alignment */
  174.                 if ((LocalChunkLength % 2) != 0)
  175.                     {
  176.                         LocalChunkLength += 1;
  177.                     }
  178.                 FormChunkLength -= LocalChunkLength;
  179.  
  180.                 /* decode the chunk */
  181.                 if (MemEqu(CharBuff,"COMM",4))
  182.                     {
  183.                         unsigned long                Exponent;
  184.                         unsigned long                Mantissa;
  185.                         char                                StupidExtendedThang[10];
  186.  
  187.                         if (!IsAnAIFFCFile)
  188.                             {
  189.                                 unsigned short        ShortInteger;
  190.  
  191.                                 /*   Common Chunk for AIFF files */
  192.                                 /*     "COMM" */
  193.                                 /*     4-byte big endian length. */
  194.                                 /*        always 18 for AIFF files */
  195.                                 if (LocalChunkLength != 18)
  196.                                     {
  197.                                         goto UnknownAIFFFilePoint;
  198.                                     }
  199.  
  200.                                 /*     2-byte big endian number of channels */
  201.                                 if (!ReadBufferedUnsignedShortBigEndian(File,&ShortInteger))
  202.                                     {
  203.                                         goto DiskErrorPoint1;
  204.                                     }
  205.                                 switch (ShortInteger)
  206.                                     {
  207.                                         default:
  208.                                             goto UnknownAIFFFilePoint;
  209.                                         case 1:
  210.                                             NumChannels = eSampleMono;
  211.                                             NumChannelsIsValid = True;
  212.                                             break;
  213.                                         case 2:
  214.                                             NumChannels = eSampleStereo;
  215.                                             NumChannelsIsValid = True;
  216.                                             break;
  217.                                     }
  218.  
  219.                                 /*     4-byte big endian number of sample frames */
  220.                                 if (!ReadBufferedUnsignedLongBigEndian(File,&NumSampleFrames))
  221.                                     {
  222.                                         goto DiskErrorPoint1;
  223.                                     }
  224.                                 NumSampleFramesIsValid = True;
  225.  
  226.                                 /*     2-byte big endian number of bits per sample */
  227.                                 /*        a value in the domain 1..32 */
  228.                                 if (!ReadBufferedUnsignedShortBigEndian(File,&ShortInteger))
  229.                                     {
  230.                                         goto DiskErrorPoint1;
  231.                                     }
  232.                                 switch (ShortInteger)
  233.                                     {
  234.                                         default:
  235.                                             goto UnknownAIFFFilePoint;
  236.                                         case 1: case 2: case 3: case 4:
  237.                                         case 5: case 6: case 7: case 8:
  238.                                             NumBits = 8;
  239.                                             NumBitsIsValid = True;
  240.                                             break;
  241.                                         case 9: case 10: case 11: case 12:
  242.                                         case 13: case 14: case 15: case 16:
  243.                                             NumBits = 16;
  244.                                             NumBitsIsValid = True;
  245.                                             break;
  246.                                     }
  247.  
  248.                                 /*     10-byte extended precision number of frames per second */
  249.                                 if (!ReadBufferedInput(File,10,StupidExtendedThang))
  250.                                     {
  251.                                         goto DiskErrorPoint1;
  252.                                     }
  253.                             }
  254.                          else
  255.                             {
  256.                                 unsigned short            ShortInteger;
  257.                                 long                                Dumper;
  258.  
  259.                                 /*   Common Chunk for AIFF-C files */
  260.                                 /*     "COMM" */
  261.                                 /*     4-byte big endian length. */
  262.                                 /*        always 18 for AIFF files */
  263.                                 if (LocalChunkLength < 22)
  264.                                     {
  265.                                         goto UnknownAIFFFilePoint;
  266.                                     }
  267.  
  268.                                 /*     2-byte big endian number of channels */
  269.                                 if (!ReadBufferedUnsignedShortBigEndian(File,&ShortInteger))
  270.                                     {
  271.                                         goto DiskErrorPoint1;
  272.                                     }
  273.                                 switch (ShortInteger)
  274.                                     {
  275.                                         default:
  276.                                             goto UnknownAIFFFilePoint;
  277.                                         case 1:
  278.                                             NumChannels = eSampleMono;
  279.                                             NumChannelsIsValid = True;
  280.                                             break;
  281.                                         case 2:
  282.                                             NumChannels = eSampleStereo;
  283.                                             NumChannelsIsValid = True;
  284.                                             break;
  285.                                     }
  286.  
  287.                                 /*     4-byte big endian number of sample frames */
  288.                                 if (!ReadBufferedUnsignedLongBigEndian(File,&NumSampleFrames))
  289.                                     {
  290.                                         goto DiskErrorPoint1;
  291.                                     }
  292.                                 NumSampleFramesIsValid = True;
  293.  
  294.                                 /*     2-byte big endian number of bits per sample */
  295.                                 /*        a value in the domain 1..32 */
  296.                                 if (!ReadBufferedUnsignedShortBigEndian(File,&ShortInteger))
  297.                                     {
  298.                                         goto DiskErrorPoint1;
  299.                                     }
  300.                                 switch (ShortInteger)
  301.                                     {
  302.                                         default:
  303.                                             goto UnknownAIFFFilePoint;
  304.                                         case 1: case 2: case 3: case 4:
  305.                                         case 5: case 6: case 7: case 8:
  306.                                             NumBits = 8;
  307.                                             NumBitsIsValid = True;
  308.                                             break;
  309.                                         case 9: case 10: case 11: case 12:
  310.                                         case 13: case 14: case 15: case 16:
  311.                                             NumBits = 16;
  312.                                             NumBitsIsValid = True;
  313.                                             break;
  314.                                     }
  315.  
  316.                                 /*     10-byte extended precision number of frames per second */
  317.                                 if (!ReadBufferedInput(File,10,StupidExtendedThang))
  318.                                     {
  319.                                         goto DiskErrorPoint1;
  320.                                     }
  321.  
  322.                                 /*     4-byte character code ID for the compression method */
  323.                                 /*        "NONE" means there is no compression method used */
  324.                                 if (!ReadBufferedInput(File,4,CharBuff))
  325.                                     {
  326.                                         goto DiskErrorPoint1;
  327.                                     }
  328.                                 if (!MemEqu(CharBuff,"NONE",4))
  329.                                     {
  330.                                         goto UnknownAIFFFilePoint;
  331.                                     }
  332.  
  333.                                 /*     some characters in a string identifying the compression method */
  334.                                 /*        this must be padded to an even number of bytes, but the pad is */
  335.                                 /*        NOT included in the length descriptor for the chunk. */
  336.                                 /*        for uncompressed data, the string should be */
  337.                                 /*        "\x0enot compressed\x00", including the null, for 16 bytes. */
  338.                                 /*        the total chunk length is thus 38 bytes. */
  339.                                 for (Dumper = 0; Dumper < LocalChunkLength - 22; Dumper += 1)
  340.                                     {
  341.                                         unsigned char                Stupid;
  342.  
  343.                                         if (!ReadBufferedUnsignedChar(File,&Stupid))
  344.                                             {
  345.                                                 goto DiskErrorPoint1;
  346.                                             }
  347.                                     }
  348.                             }
  349.  
  350.                         /* extended 22050 = 400D AC44000000000000 */
  351.                         /* extended 22051 = 400D AC46000000000000 */
  352.                         /* extended 44100 = 400E AC44000000000000 */
  353.                         /* extended 44101 = 400E AC45000000000000 */
  354.                         Exponent = (((long)StupidExtendedThang[0] & 0xff) << 8)
  355.                             | ((long)StupidExtendedThang[1] & 0xff);
  356.                         Mantissa = (((long)StupidExtendedThang[2] & 0xff) << 24)
  357.                             | (((long)StupidExtendedThang[3] & 0xff) << 16)
  358.                             | (((long)StupidExtendedThang[4] & 0xff) << 8)
  359.                             | ((long)StupidExtendedThang[5] & 0xff);
  360.                         SamplingRate = (Mantissa >> (0x401e - Exponent));
  361.                         if (SamplingRate < MINSAMPLINGRATE)
  362.                             {
  363.                                 SamplingRate = MINSAMPLINGRATE;
  364.                             }
  365.                         if (SamplingRate > MAXSAMPLINGRATE)
  366.                             {
  367.                                 SamplingRate = MAXSAMPLINGRATE;
  368.                             }
  369.                         SamplingRateIsValid = True;
  370.                     }
  371.                 else if (MemEqu(CharBuff,"SSND",4))
  372.                     {
  373.                         unsigned long                AlignmentFactor;
  374.                         unsigned long                OffsetToFirstByte;
  375.                         MyBoolean                        OddNumberOfSoundBytes;
  376.                         MyBoolean                        Cancelling = False;
  377.  
  378.                         /*   Sound Data Chunk */
  379.                         /*     "SSND" */
  380.                         /*     4-byte big endian number of bytes in sample data array */
  381.  
  382.                         /*     4-byte big endian offset to the first byte of sample data in the array */
  383.                         if (!ReadBufferedUnsignedLongBigEndian(File,&OffsetToFirstByte))
  384.                             {
  385.                                 goto DiskErrorPoint1;
  386.                             }
  387.                         if (OffsetToFirstByte != 0)
  388.                             {
  389.                                 goto UnknownAIFFFilePoint;
  390.                             }
  391.  
  392.                         /*     4-byte big endian number of bytes to which the sound data is aligned. */
  393.                         if (!ReadBufferedUnsignedLongBigEndian(File,&AlignmentFactor))
  394.                             {
  395.                                 goto DiskErrorPoint1;
  396.                             }
  397.                         if (AlignmentFactor != 0)
  398.                             {
  399.                                 goto UnknownAIFFFilePoint;
  400.                             }
  401.  
  402.                         /*     any length vector of raw sound data. */
  403.                         /*        this must be padded to an even number of bytes, but the pad is */
  404.                         /*        NOT included in the length descriptor for the chunk. */
  405.                         /*        Samples are stored in an integral number of bytes, the smallest that */
  406.                         /*        is required for the specified number of bits.  If this is not an even */
  407.                         /*        multiple of 8, then the data is shifted left and the low bits are zeroed */
  408.                         /*        Multichannel sound is interleaved with the left channel first. */
  409.                         /* now, deal with the stuff we just got */
  410.                         if (!NumBitsIsValid || !NumChannelsIsValid
  411.                             || !SamplingRateIsValid || !NumSampleFramesIsValid)
  412.                             {
  413.                                 goto UnknownAIFFFilePoint;
  414.                             }
  415.                         LocalChunkLength -= 8; /* chop off alignment & offset from length */
  416.                         OddNumberOfSoundBytes = ((LocalChunkLength & 1) != 0);
  417.                         if (!OpenSoundChannel(SamplingRate,
  418.                             (NumChannels == eSampleStereo) ? eStereo : eMono,
  419.                             (NumBits == 8) ? e8bit : e16bit,
  420.                             FRAMESPERBUFFER,NUMBEROFBUFFERS,INITIALNUMBUFFERS))
  421.                             {
  422.                                 AlertHalt("Unable to open the sound output device.",NIL);
  423.                             }
  424.                          else
  425.                             {
  426.                                 void*                            Buffer;
  427.                                 long                            UsedBufferFrames;
  428.                                 long                            FrameCount;
  429.                                 void*                            RawData;
  430.  
  431.                                 Buffer = NIL;
  432.                                 FrameCount = 0;
  433.                                 switch (NumChannels)
  434.                                     {
  435.                                         default:
  436.                                             EXECUTE(PRERR(ForceAbort,"PlayAIFFFile:  bad num channels"));
  437.                                             break;
  438.                                         case eSampleMono:
  439.                                             switch (NumBits)
  440.                                                 {
  441.                                                     default:
  442.                                                         EXECUTE(PRERR(ForceAbort,"PlayAIFFFile:  bad num bits"));
  443.                                                         break;
  444.                                                     case 8:
  445.                                                         RawData = AllocPtrCanFail(FRAMESPERBUFFER,
  446.                                                             "PlayAIFFFile Temp Buffer");
  447.                                                         if (RawData == NIL)
  448.                                                             {
  449.                                                                 AlertHalt("There is not enough memory available "
  450.                                                                     "to play the file.",NIL);
  451.                                                                 return;
  452.                                                             }
  453.                                                         while (LocalChunkLength > 0)
  454.                                                             {
  455.                                                                 long                        BytesThisTime;
  456.  
  457.                                                                 /* make sure there is a buffer to use */
  458.                                                                 while (Buffer == NIL)
  459.                                                                     {
  460.                                                                         Buffer = CheckOutSoundBuffer();
  461.                                                                         if (((Buffer != NIL)
  462.                                                                             && RelinquishCPUJudiciouslyCheckCancel())
  463.                                                                             || ((Buffer == NIL)
  464.                                                                             && RelinquishCPUCheckCancel()))
  465.                                                                             {
  466.                                                                                 Cancelling = True;
  467.                                                                                 goto CancelPoint;
  468.                                                                             }
  469.                                                                     }
  470.                                                                 /* fill the buffer in with data */
  471.                                                                 if (LocalChunkLength < FRAMESPERBUFFER)
  472.                                                                     {
  473.                                                                         BytesThisTime = LocalChunkLength;
  474.                                                                     }
  475.                                                                  else
  476.                                                                     {
  477.                                                                         BytesThisTime = FRAMESPERBUFFER;
  478.                                                                     }
  479.                                                                 LocalChunkLength -= BytesThisTime;
  480.                                                                 PRNGCHK(RawData,RawData,BytesThisTime);
  481.                                                                 if (!ReadBufferedInput(File,BytesThisTime,(char*)RawData))
  482.                                                                     {
  483.                                                                      DiskErrorDuringPlaybackPoint:
  484.                                                                         AlertHalt("A disk error occurred during playback.",NIL);
  485.                                                                         DiskErrorOccurred = True;
  486.                                                                         Cancelling = True;
  487.                                                                         goto CancelPoint;
  488.                                                                     }
  489.                                                                 UsedBufferFrames = 0;
  490.                                                                 while (UsedBufferFrames < BytesThisTime)
  491.                                                                     {
  492.                                                                         PRNGCHK(Buffer,&(((signed char*)Buffer)[UsedBufferFrames]),
  493.                                                                             sizeof(((signed char*)Buffer)[UsedBufferFrames]));
  494.                                                                         ((signed char*)Buffer)[UsedBufferFrames]
  495.                                                                             = ((signed char*)RawData)[UsedBufferFrames];
  496.                                                                         UsedBufferFrames += 1;
  497.                                                                     }
  498.                                                                 /* submit the buffer */
  499.                                                                 FrameCount += UsedBufferFrames;
  500.                                                                 UpdateSynthWindow(Window,SamplingRate,FrameCount,0,False);
  501.                                                                 SubmitBuffer((char*)Buffer,UsedBufferFrames,NIL,NIL);
  502.                                                                 Buffer = NIL;
  503.                                                             }
  504.                                                         break;
  505.                                                     case 16:
  506.                                                         RawData = AllocPtrCanFail(FRAMESPERBUFFER * 2,
  507.                                                             "PlayAIFFFile Temp Buffer");
  508.                                                         if (RawData == NIL)
  509.                                                             {
  510.                                                                 AlertHalt("There is not enough memory available "
  511.                                                                     "to play the file.",NIL);
  512.                                                                 return;
  513.                                                             }
  514.                                                         while (LocalChunkLength > 0)
  515.                                                             {
  516.                                                                 long                        BytesThisTime;
  517.  
  518.                                                                 /* make sure there is a buffer to use */
  519.                                                                 while (Buffer == NIL)
  520.                                                                     {
  521.                                                                         Buffer = CheckOutSoundBuffer();
  522.                                                                         if (((Buffer != NIL)
  523.                                                                             && RelinquishCPUJudiciouslyCheckCancel())
  524.                                                                             || ((Buffer == NIL)
  525.                                                                             && RelinquishCPUCheckCancel()))
  526.                                                                             {
  527.                                                                                 Cancelling = True;
  528.                                                                                 goto CancelPoint;
  529.                                                                             }
  530.                                                                     }
  531.                                                                 /* fill the buffer in with data */
  532.                                                                 if (LocalChunkLength < FRAMESPERBUFFER * 2)
  533.                                                                     {
  534.                                                                         BytesThisTime = LocalChunkLength;
  535.                                                                     }
  536.                                                                  else
  537.                                                                     {
  538.                                                                         BytesThisTime = FRAMESPERBUFFER * 2;
  539.                                                                     }
  540.                                                                 LocalChunkLength -= BytesThisTime;
  541.                                                                 PRNGCHK(RawData,RawData,BytesThisTime);
  542.                                                                 if (!ReadBufferedInput(File,BytesThisTime,(char*)RawData))
  543.                                                                     {
  544.                                                                         goto DiskErrorDuringPlaybackPoint;
  545.                                                                     }
  546.                                                                 UsedBufferFrames = 0;
  547.                                                                 while (UsedBufferFrames < BytesThisTime / 2)
  548.                                                                     {
  549.                                                                         PRNGCHK(Buffer,&(((signed short*)Buffer)[UsedBufferFrames]),
  550.                                                                             sizeof(((signed short*)Buffer)[UsedBufferFrames]));
  551.                                                                         ((signed short*)Buffer)[UsedBufferFrames]
  552.                                                                             = (((short)((signed char*)RawData)[2 * UsedBufferFrames] & 0xff) << 8)
  553.                                                                             | (((signed char*)RawData)[2 * UsedBufferFrames + 1] & 0xff);
  554.                                                                         UsedBufferFrames += 1;
  555.                                                                     }
  556.                                                                 /* submit the buffer */
  557.                                                                 FrameCount += UsedBufferFrames;
  558.                                                                 UpdateSynthWindow(Window,SamplingRate,FrameCount,0,False);
  559.                                                                 SubmitBuffer((char*)Buffer,UsedBufferFrames,NIL,NIL);
  560.                                                                 Buffer = NIL;
  561.                                                             }
  562.                                                         break;
  563.                                                 }
  564.                                             break;
  565.                                         case eSampleStereo:
  566.                                             switch (NumBits)
  567.                                                 {
  568.                                                     default:
  569.                                                         EXECUTE(PRERR(ForceAbort,"PlayAIFFFile:  bad num bits"));
  570.                                                         break;
  571.                                                     case 8:
  572.                                                         RawData = AllocPtrCanFail(FRAMESPERBUFFER * 2,
  573.                                                             "PlayAIFFFile Temp Buffer");
  574.                                                         if (RawData == NIL)
  575.                                                             {
  576.                                                                 AlertHalt("There is not enough memory available "
  577.                                                                     "to play the file.",NIL);
  578.                                                                 return;
  579.                                                             }
  580.                                                         while (LocalChunkLength > 0)
  581.                                                             {
  582.                                                                 long                        BytesThisTime;
  583.  
  584.                                                                 /* make sure there is a buffer to use */
  585.                                                                 while (Buffer == NIL)
  586.                                                                     {
  587.                                                                         Buffer = CheckOutSoundBuffer();
  588.                                                                         if (((Buffer != NIL)
  589.                                                                             && RelinquishCPUJudiciouslyCheckCancel())
  590.                                                                             || ((Buffer == NIL)
  591.                                                                             && RelinquishCPUCheckCancel()))
  592.                                                                             {
  593.                                                                                 Cancelling = True;
  594.                                                                                 goto CancelPoint;
  595.                                                                             }
  596.                                                                     }
  597.                                                                 /* fill the buffer in with data */
  598.                                                                 if (LocalChunkLength < FRAMESPERBUFFER * 2)
  599.                                                                     {
  600.                                                                         BytesThisTime = LocalChunkLength;
  601.                                                                     }
  602.                                                                  else
  603.                                                                     {
  604.                                                                         BytesThisTime = FRAMESPERBUFFER * 2;
  605.                                                                     }
  606.                                                                 LocalChunkLength -= BytesThisTime;
  607.                                                                 PRNGCHK(RawData,RawData,BytesThisTime);
  608.                                                                 if (!ReadBufferedInput(File,BytesThisTime,(char*)RawData))
  609.                                                                     {
  610.                                                                         goto DiskErrorDuringPlaybackPoint;
  611.                                                                     }
  612.                                                                 UsedBufferFrames = 0;
  613.                                                                 while (UsedBufferFrames < BytesThisTime)
  614.                                                                     {
  615.                                                                         PRNGCHK(Buffer,&(((signed char*)Buffer)[UsedBufferFrames]),
  616.                                                                             sizeof(((signed char*)Buffer)[UsedBufferFrames]));
  617.                                                                         ((signed char*)Buffer)[UsedBufferFrames]
  618.                                                                             = ((signed char*)RawData)[UsedBufferFrames];
  619.                                                                         UsedBufferFrames += 1;
  620.                                                                     }
  621.                                                                 /* submit the buffer */
  622.                                                                 FrameCount += UsedBufferFrames / 2;
  623.                                                                 UpdateSynthWindow(Window,SamplingRate,FrameCount,0,False);
  624.                                                                 SubmitBuffer((char*)Buffer,UsedBufferFrames / 2,NIL,NIL);
  625.                                                                 Buffer = NIL;
  626.                                                             }
  627.                                                         break;
  628.                                                     case 16:
  629.                                                         RawData = AllocPtrCanFail(FRAMESPERBUFFER * 4,
  630.                                                             "PlayAIFFFile Temp Buffer");
  631.                                                         if (RawData == NIL)
  632.                                                             {
  633.                                                                 AlertHalt("There is not enough memory available "
  634.                                                                     "to play the file.",NIL);
  635.                                                                 return;
  636.                                                             }
  637.                                                         while (LocalChunkLength > 0)
  638.                                                             {
  639.                                                                 long                        BytesThisTime;
  640.  
  641.                                                                 /* make sure there is a buffer to use */
  642.                                                                 while (Buffer == NIL)
  643.                                                                     {
  644.                                                                         Buffer = CheckOutSoundBuffer();
  645.                                                                         if (((Buffer != NIL)
  646.                                                                             && RelinquishCPUJudiciouslyCheckCancel())
  647.                                                                             || ((Buffer == NIL)
  648.                                                                             && RelinquishCPUCheckCancel()))
  649.                                                                             {
  650.                                                                                 Cancelling = True;
  651.                                                                                 goto CancelPoint;
  652.                                                                             }
  653.                                                                     }
  654.                                                                 /* fill the buffer in with data */
  655.                                                                 if (LocalChunkLength < FRAMESPERBUFFER * 4)
  656.                                                                     {
  657.                                                                         BytesThisTime = LocalChunkLength;
  658.                                                                     }
  659.                                                                  else
  660.                                                                     {
  661.                                                                         BytesThisTime = FRAMESPERBUFFER * 4;
  662.                                                                     }
  663.                                                                 LocalChunkLength -= BytesThisTime;
  664.                                                                 PRNGCHK(RawData,RawData,BytesThisTime);
  665.                                                                 if (!ReadBufferedInput(File,BytesThisTime,(char*)RawData))
  666.                                                                     {
  667.                                                                         goto DiskErrorDuringPlaybackPoint;
  668.                                                                     }
  669.                                                                 UsedBufferFrames = 0;
  670.                                                                 while (UsedBufferFrames < BytesThisTime / 2)
  671.                                                                     {
  672.                                                                         PRNGCHK(Buffer,&(((signed short*)Buffer)[UsedBufferFrames]),
  673.                                                                             sizeof(((signed short*)Buffer)[UsedBufferFrames]));
  674.                                                                         ((signed short*)Buffer)[UsedBufferFrames]
  675.                                                                             = (((short)((signed char*)RawData)[2 * UsedBufferFrames] & 0xff) << 8)
  676.                                                                             | (((signed char*)RawData)[2 * UsedBufferFrames + 1] & 0xff);
  677.                                                                         UsedBufferFrames += 1;
  678.                                                                     }
  679.                                                                 /* submit the buffer */
  680.                                                                 FrameCount += UsedBufferFrames / 2;
  681.                                                                 UpdateSynthWindow(Window,SamplingRate,FrameCount,0,False);
  682.                                                                 SubmitBuffer((char*)Buffer,UsedBufferFrames / 2,NIL,NIL);
  683.                                                                 Buffer = NIL;
  684.                                                             }
  685.                                                         break;
  686.                                                 }
  687.                                             break;
  688.                                     }
  689.                                 if (Buffer != NIL)
  690.                                     {
  691.                                         SubmitBuffer((char*)Buffer,UsedBufferFrames,NIL,NIL);
  692.                                         Buffer = NIL;
  693.                                     }
  694.                                 if (OddNumberOfSoundBytes)
  695.                                     {
  696.                                         unsigned char                    StupidChar;
  697.  
  698.                                         if (!ReadBufferedUnsignedChar(File,&StupidChar))
  699.                                             {
  700.                                                 DiskErrorOccurred = True;
  701.                                             }
  702.                                     }
  703.                              CancelPoint: /* jump here to cancel playback */
  704.                                 ReleasePtr((char*)RawData);
  705.                                 if (Cancelling)
  706.                                     {
  707.                                         KillSoundChannel(); /* don't wait */
  708.                                     }
  709.                                  else
  710.                                     {
  711.                                         CloseSoundChannel(NIL,NIL);
  712.                                     }
  713.                             }
  714.                     }
  715.                 else
  716.                     {
  717.                         /* just read the data & get rid of it */
  718.                         while (LocalChunkLength > 0)
  719.                             {
  720.                                 unsigned char                Stupid;
  721.  
  722.                                 if (!ReadBufferedUnsignedChar(File,&Stupid))
  723.                                     {
  724.                                         goto DiskErrorPoint1;
  725.                                     }
  726.                                 LocalChunkLength -= 1;
  727.                             }
  728.                     }
  729.             }
  730.         if (DiskErrorOccurred)
  731.             {
  732.                 goto DiskErrorPoint1;
  733.             }
  734.     }
  735.  
  736.  
  737. /* ask the user for a file, and then try to play back its contents */
  738. void                                    PlayAIFFFile(void)
  739.     {
  740.         FileSpec*                    WhereIsTheFile;
  741.  
  742.         WhereIsTheFile = GetFileAny();
  743.         if (WhereIsTheFile != NIL)
  744.             {
  745.                 PlayAIFFFileSpec(WhereIsTheFile);
  746.                 DisposeFileSpec(WhereIsTheFile);
  747.             }
  748.     }
  749.  
  750.  
  751. /* play specified AIFF file */
  752. void                                    PlayAIFFFileSpec(struct FileSpec* Where)
  753.     {
  754.         FileType*                    FileDesc;
  755.  
  756.         CheckPtrExistence(Where);
  757.         if (OpenFile(Where,&FileDesc,eReadOnly))
  758.             {
  759.                 BufferedInputRec*        File;
  760.  
  761.                 File = NewBufferedInput(FileDesc);
  762.                 if (File != NIL)
  763.                     {
  764.                         SynthWinRec*                Window;
  765.  
  766.                         Window = NewSynthWindow(4,False/*don't show clipping*/);
  767.                         if (Window != NIL)
  768.                             {
  769.                                 PlayTheFile(File,Window);
  770.                                 DisposeSynthWindow(Window);
  771.                             }
  772.                          else
  773.                             {
  774.                                 AlertHalt("There is not enough memory available to play the file.",NIL);
  775.                             }
  776.                         EndBufferedInput(File);
  777.                     }
  778.                  else
  779.                     {
  780.                         AlertHalt("There is not enough memory available to play the file.",NIL);
  781.                     }
  782.                 CloseFile(FileDesc);
  783.             }
  784.          else
  785.             {
  786.                 AlertHalt("Unable to open the file for reading.",NIL);
  787.             }
  788.     }
  789.